package ipmsg.gui;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.Socket;

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import javax.swing.LayoutStyle;

import ipmsg.IpmsgConstants;
import ipmsg.etc.Command;
import ipmsg.etc.FileLinkList;
import ipmsg.etc.FileNode;
import ipmsg.etc.GlobalVar;

public class RecvingFile extends javax.swing.JFrame {
	/**
	 * 
	 */
	private static final long serialVersionUID = -4066571529751106844L;
	private FileLinkList flist;
	private int fileSelection;
	private String savePath;
	InterfaceSetVisible_GetRecFiles inter;
	boolean replace;
	boolean cancelSafe = false;
	boolean cancelNow = false;

	private Socket socket;

	private DataInputStream inputStream;
	private DataOutputStream outputStream;
	private DataOutputStream fileOut;
	private JButton jButton1;
	private JButton jButton2;

	public RecvingFile(FileLinkList flist, int fileSelection, String savePath, InterfaceSetVisible_GetRecFiles inter,
			boolean replace) {
		this.fileSelection = fileSelection;
		this.flist = flist;
		this.savePath = savePath;
		this.replace = replace;
		this.inter = inter;
		initComponents();
		new Thread(new RecvingDeamon()).start();
	}

	private void initComponents() {
		jPanel1 = new JPanel();
		jScrollPane1 = new JScrollPane();
		jTextArea1 = new JTextArea();
		jPanel2 = new JPanel();
		jButton1 = new JButton();
		jButton2 = new JButton();
		jLabel1 = new JLabel();
		jToggleButton1 = new JToggleButton();

		setDefaultCloseOperation(0);
		setTitle("接收文件");
		addWindowListener(new java.awt.event.WindowAdapter() {
			public void windowClosing(WindowEvent evt) {
				RecvingFile.this.formWindowClosing(evt);
			}

		});
		jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("接收文件列表"));

		jTextArea1.setColumns(20);
		jTextArea1.setEditable(false);
		jTextArea1.setRows(5);
		jScrollPane1.setViewportView(jTextArea1);

		GroupLayout jPanel1Layout = new GroupLayout(jPanel1);
		jPanel1.setLayout(jPanel1Layout);
		jPanel1Layout.setHorizontalGroup(jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
				.addComponent(jScrollPane1, -1, 352, 32767));

		jPanel1Layout.setVerticalGroup(jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
				.addComponent(jScrollPane1, -1, 172, 32767));

		getContentPane().add(jPanel1, "Center");

		jButton1.setText("立即终止");
		jButton1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				RecvingFile.this.jButton1ActionPerformed(evt);
			}

		});
		jButton2.setText("安全终止");
		jButton2.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				RecvingFile.this.jButton2ActionPerformed(evt);
			}

		});
		jLabel1.setText("0%");

		jToggleButton1.setText("关闭输出");
		jToggleButton1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				RecvingFile.this.jToggleButton1ActionPerformed(evt);
			}

		});
		GroupLayout jPanel2Layout = new GroupLayout(jPanel2);
		jPanel2.setLayout(jPanel2Layout);
		jPanel2Layout.setHorizontalGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
				.addGroup(jPanel2Layout.createSequentialGroup().addContainerGap().addComponent(jLabel1, -1, 89, 32767)
						.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(jToggleButton1)
						.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(jButton2)
						.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(jButton1)
						.addContainerGap()));

		jPanel2Layout
				.setVerticalGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
						.addGroup(jPanel2Layout.createSequentialGroup().addContainerGap()
								.addGroup(jPanel2Layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
										.addComponent(jButton2).addComponent(jButton1).addComponent(jLabel1)
										.addComponent(jToggleButton1))
								.addContainerGap(-1, 32767)));

		getContentPane().add(jPanel2, "South");

		Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
		setBounds(((screenSize.width - 376)) / (2), ((screenSize.height - 277)) / (2), 376, 277);
	}

	private void jButton1ActionPerformed(ActionEvent evt) {
		exit();
	}

	private void jButton2ActionPerformed(ActionEvent evt) {
		cancelSafe = true;
	}

	private void formWindowClosing(WindowEvent evt) {
		exit();
	}

	private void jToggleButton1ActionPerformed(ActionEvent evt) {
		if (jToggleButton1.isSelected()) {
			jToggleButton1.setText("开启输出");
		} else {
			jToggleButton1.setText("关闭输出");
		}
	}

	private JLabel jLabel1;

	private JPanel jPanel1;

	private JPanel jPanel2;

	private JScrollPane jScrollPane1;

	private JTextArea jTextArea1;

	private JToggleButton jToggleButton1;

	private void exit() {
		if (!UtilityGui.confirm(this, "立即终止", "正在传输中，是否继续？")) {
			return;
		}
		cancelNow = true;
		dispose();
		closeSocket();
		exitNormal();
	}

	class RecvingDeamon extends Thread {
		RecvingDeamon() {
		}

		public void run() {
			Command com = new Command(96);
			try {
				if (fileSelection == flist.getFiles().size()) {
					for (int i = 0; i < fileSelection; i++) {
						if (!((FileNode) flist.getFiles().get(i)).isIsTransfered()) {
							RecvingFile.this.initSocket();

							com.setAdditional(Integer.toHexString(flist.getPacketNo()) + ":" + Integer.toHexString(i)
									+ ":" + Integer.toHexString(0) + ":");

							if (((FileNode) flist.getFiles().get(i)).getFileKind() == 1) {

								com.resetFlag(96);
								outputStream.write(com.exportToBuf());
								outputStream.flush();

								getRegularFile(getPath(savePath, ((FileNode) flist.getFiles().get(i)).getFileName()),
										((FileNode) flist.getFiles().get(i)).getFileLen());

							} else if (((FileNode) flist.getFiles().get(i)).getFileKind() == 2) {

								com.resetFlag(98);
								outputStream.write(com.exportToBuf());
								outputStream.flush();
								getDir();
							}
							RecvingFile.this.closeSocket();
							if (!cancelNow)
								((FileNode) flist.getFiles().get(i)).setIsTransfered(true);
							if (cancelSafe) {
								break;
							}
						}
					}
				} else {
					RecvingFile.this.initSocket();

					com.setAdditional(Integer.toHexString(flist.getPacketNo()) + ":"
							+ Integer.toHexString(fileSelection) + ":" + Integer.toHexString(0) + ":");

					if (((FileNode) flist.getFiles().get(fileSelection)).getFileKind() == 1) {

						com.resetFlag(96);
						outputStream.write(com.exportToBuf());
						outputStream.flush();

						getRegularFile(
								getPath(savePath, ((FileNode) flist.getFiles().get(fileSelection)).getFileName()),
								((FileNode) flist.getFiles().get(fileSelection)).getFileLen());

					} else if (((FileNode) flist.getFiles().get(fileSelection)).getFileKind() == 2) {

						com.resetFlag(98);
						outputStream.write(com.exportToBuf());
						outputStream.flush();
						getDir();
					}
					RecvingFile.this.closeSocket();
					if (!cancelNow) {
						((FileNode) flist.getFiles().get(fileSelection)).setIsTransfered(true);
					}
				}
				RecvingFile.this.exitNormal();
			} catch (IOException ex) {
				System.out.println("error");
			}
		}

		private String getPath(String path, String filename) {
			if (replace) {
				return path + GlobalVar.FILE_PATH_DELIMITER + filename;
			}
			while (new File(path + GlobalVar.FILE_PATH_DELIMITER + filename).exists()) {
				filename = "[LanMsg]" + filename;
			}
			return path + GlobalVar.FILE_PATH_DELIMITER + filename;
		}

		private void getRegularFile(String path, long fileLen) {
			if (!jToggleButton1.isSelected())
				RecvingFile.this.appendMsg("接收文件 ： " + path);
			byte[] buf = new byte[8092];
			int read = -1;
			int readonce = 8092;
			long rest = fileLen;
			try {
				fileOut = new DataOutputStream(new java.io.BufferedOutputStream(
						new java.io.BufferedOutputStream(new java.io.FileOutputStream(path))));

				jLabel1.setText("0%");
				long percent = fileLen / 100L > 8092L ? fileLen / 100L : 8092L;

				long recvPercent = percent;
				int counter = 1;

				do {
					if (inputStream != null) {
						if (readonce > rest)
							readonce = (int) rest;
						read = inputStream.read(buf, 0, readonce);
					}
					if (read == -1) {
						break;
					}
					rest -= read;
					fileOut.write(buf, 0, read);

					if ((!jToggleButton1.isSelected()) && (fileLen - rest > recvPercent)) {
						recvPercent += percent;
						RecvingFile.updatePercent up = new RecvingFile.updatePercent();
						percent = counter;
						javax.swing.SwingUtilities.invokeLater(up);
						counter++;
					}

				} while (rest > 0L);
				jLabel1.setText("100%");

				fileOut.flush();
				fileOut.close();
			} catch (IOException ex) {
			}
		}

		private void getDir() {
			String path = savePath;

			int depth = 0;
			do {
				FileNode fnode = getHeader();
				if (fnode == null)
					break;
				switch (fnode.getFileKind()) {
				case 1:
					getRegularFile(path + GlobalVar.FILE_PATH_DELIMITER + fnode.getFileName(), fnode.getFileLen());

					break;
				case 2:
					if (depth == 0)
						path = getPath(path, fnode.getFileName());
					else {
						path = path + GlobalVar.FILE_PATH_DELIMITER + fnode.getFileName();
					}

					if (!jToggleButton1.isSelected()) {
						RecvingFile.this.appendMsg("进入目录 ： " + path);
					}
					new File(path).mkdir();
					depth++;
					break;
				case 3:
					if (!jToggleButton1.isSelected())
						RecvingFile.this.appendMsg("退出目录 ： " + path);
					path = getParentDir(path);
					depth--;
					break;
				default:
					System.out.println("wrong file");
				}
			} while (depth > 0);
		}

		private String getParentDir(String str) {
			int len = str.lastIndexOf(GlobalVar.FILE_PATH_DELIMITER);
			if (len < 0)
				return null;
			return str.substring(0, len);
		}

		private FileNode getHeader() {
			try {
				String head = ipmsg.network.UtilityNet.readDelimiter(inputStream, 100);
				if (head == null) {
					return null;
				}
				int count = Integer.parseInt(head, 16) - 5;
				if (count <= 0) {
					return null;
				}
				byte[] headBuf = new byte[count];
				if (inputStream.read(headBuf, 0, count) < 0) {
					return null;
				}
				head = new String(headBuf, GlobalVar.CHARACTER_ENCODING);

				FileNode fnode = new FileNode();
				for (int i = 0; i < 3;) {
					int pos;
					if ((pos = head.indexOf(":")) < 0) {
						return null;
					}
					count = 1;
					while (head.charAt(++pos) == ':') {
						count++;
					}
					if (count % 2 != 0) {

						switch (i) {
						case 0:
							fnode.setFileName(head.substring(0, pos - 1));
							break;
						case 1:
							if (!fnode.setFileLen(head.substring(0, pos - 1))) {
								return null;
							}
							break;
						case 2:
							if (!fnode.setFileKind(head.substring(0, pos - 1)))
								return null;
							break;
						}
						head = head.substring(pos);
						i++;
					}
				}
				return fnode;
			} catch (IOException ex) {
				return null;
			} catch (NumberFormatException e) {
			}
			return null;
		}
	}

	class updatePercent extends Thread {
		int percent;

		updatePercent() {
			super();
		}

		public void run() {
			jLabel1.setText(percent + "%");
		}
	}

	private void closeSocket() {
		try {
			outputStream.close();
			inputStream.close();
			socket.close();
		} catch (IOException ex) {
			System.out.println("error1");
		}
	}

	private void initSocket() {
		try {
			socket = new Socket(flist.getIp(), IpmsgConstants.DEFAULT_PORT);

			outputStream = new DataOutputStream(socket.getOutputStream());

			inputStream = new DataInputStream(new java.io.BufferedInputStream(socket.getInputStream()));
		} catch (Exception e) {
			System.out.println("error2");
		}
	}

	private void appendMsg(String str) {
		jTextArea1.append(str + GlobalVar.NEW_LINE);
		JScrollBar jb = jScrollPane1.getVerticalScrollBar();
		jb.setValue(jb.getMaximum());
	}

	private void exitNormal() {
		dispose();
		inter.enableVisible();
	}
}
